Refactor pthread usage of libcxx. This patch extracts out all the pthread dependencies of libcxx into the new header __threading_support. The motivation is to make it easy to re-target libcxx into platforms that do not support pthread. Original patch from Fulvio Esposito (fulvio.esposito@outlook.com) - D11781 Applied with tweaks - D19412 Change-Id: I301111f0075de93dd8129416e06babc195aa936b git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@268734 91177308-0d34-0410-b5e6-96231b3b80d8 
diff --git a/include/__config b/include/__config index a4c6cec..5fbc646 100644 --- a/include/__config +++ b/include/__config 
@@ -812,6 +812,20 @@  # define _LIBCPP_WEAK __attribute__((__weak__))  #endif   +// Thread API +#ifndef _LIBCPP_HAS_NO_THREADS +# if defined(__FreeBSD__) || \ + defined(__NetBSD__) || \ + defined(__linux__) || \ + defined(__APPLE__) || \ + defined(__CloudABI__) +# define _LIBCPP_THREAD_API_PTHREAD +# else +# error "No thread API" +# endif // _LIBCPP_THREAD_API +#endif // _LIBCPP_HAS_NO_THREADS + +  #if defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK) && !defined(_LIBCPP_HAS_NO_THREADS)  # error _LIBCPP_HAS_NO_MONOTONIC_CLOCK may only be defined when \  _LIBCPP_HAS_NO_THREADS is defined. 
diff --git a/include/__mutex_base b/include/__mutex_base index 364c69e..32536a6 100644 --- a/include/__mutex_base +++ b/include/__mutex_base 
@@ -14,9 +14,7 @@  #include <__config>  #include <chrono>  #include <system_error> -#ifndef _LIBCPP_HAS_NO_THREADS -#include <pthread.h> -#endif +#include <__threading_support>    #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)  #pragma GCC system_header @@ -36,14 +34,14 @@    class _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex  { - pthread_mutex_t __m_; + __libcpp_mutex_t __m_;    public:  _LIBCPP_INLINE_VISIBILITY  #ifndef _LIBCPP_HAS_NO_CONSTEXPR - constexpr mutex() _NOEXCEPT : __m_(PTHREAD_MUTEX_INITIALIZER) {} + constexpr mutex() _NOEXCEPT : __m_(_LIBCPP_MUTEX_INITIALIZER) {}  #else - mutex() _NOEXCEPT {__m_ = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;} + mutex() _NOEXCEPT {__m_ = (__libcpp_mutex_t)_LIBCPP_MUTEX_INITIALIZER;}  #endif  ~mutex();   @@ -56,7 +54,7 @@  bool try_lock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));  void unlock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());   - typedef pthread_mutex_t* native_handle_type; + typedef __libcpp_mutex_t* native_handle_type;  _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}  };   @@ -276,13 +274,13 @@    class _LIBCPP_TYPE_VIS condition_variable  { - pthread_cond_t __cv_; + __libcpp_condvar_t __cv_;  public:  _LIBCPP_INLINE_VISIBILITY  #ifndef _LIBCPP_HAS_NO_CONSTEXPR - constexpr condition_variable() : __cv_(PTHREAD_COND_INITIALIZER) {} + constexpr condition_variable() : __cv_(_LIBCPP_CONDVAR_INITIALIZER) {}  #else - condition_variable() {__cv_ = (pthread_cond_t)PTHREAD_COND_INITIALIZER;} + condition_variable() {__cv_ = (__libcpp_condvar_t)_LIBCPP_CONDVAR_INITIALIZER;}  #endif  ~condition_variable();   @@ -321,7 +319,7 @@  const chrono::duration<_Rep, _Period>& __d,  _Predicate __pred);   - typedef pthread_cond_t* native_handle_type; + typedef __libcpp_condvar_t* native_handle_type;  _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}    private: 
diff --git a/include/__threading_support b/include/__threading_support new file mode 100644 index 0000000..49fdca2 --- /dev/null +++ b/include/__threading_support 
@@ -0,0 +1,205 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_THREADING_SUPPORT +#define _LIBCPP_THREADING_SUPPORT + +#include <__config> + +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +#pragma GCC system_header +#endif + +#ifndef _LIBCPP_HAS_NO_THREADS + +#if defined(_LIBCPP_THREAD_API_PTHREAD) +#include <pthread.h> +#include <sched.h> +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if defined(_LIBCPP_THREAD_API_PTHREAD) + +// Mutex +#define _LIBCPP_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +typedef pthread_mutex_t __libcpp_mutex_t; + +inline _LIBCPP_ALWAYS_INLINE +int __libcpp_recursive_mutex_init(__libcpp_mutex_t* __m) +{ + pthread_mutexattr_t attr; + int __ec = pthread_mutexattr_init(&attr); + if (__ec) return __ec; + __ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + if (__ec) + { + pthread_mutexattr_destroy(&attr); + return __ec; + } + __ec = pthread_mutex_init(__m, &attr); + if (__ec) + { + pthread_mutexattr_destroy(&attr); + return __ec; + } + __ec = pthread_mutexattr_destroy(&attr); + if (__ec) + { + pthread_mutex_destroy(__m); + return __ec; + } + return 0; +} + +inline _LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_lock(__libcpp_mutex_t* __m) +{ + return pthread_mutex_lock(__m); +} + +inline _LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_trylock(__libcpp_mutex_t* __m) +{ + return pthread_mutex_trylock(__m); +} + +inline _LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_unlock(__libcpp_mutex_t* __m) +{ + return pthread_mutex_unlock(__m); +} + +inline _LIBCPP_ALWAYS_INLINE +int __libcpp_mutex_destroy(__libcpp_mutex_t* __m) +{ + return pthread_mutex_destroy(__m); +} + +// Condition variable +#define _LIBCPP_CONDVAR_INITIALIZER PTHREAD_COND_INITIALIZER +typedef pthread_cond_t __libcpp_condvar_t; + +inline _LIBCPP_ALWAYS_INLINE +int __libcpp_condvar_signal(__libcpp_condvar_t* __cv) +{ + return pthread_cond_signal(__cv); +} + +inline _LIBCPP_ALWAYS_INLINE +int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv) +{ + return pthread_cond_broadcast(__cv); +} + +inline _LIBCPP_ALWAYS_INLINE +int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m) +{ + return pthread_cond_wait(__cv, __m); +} + +inline _LIBCPP_ALWAYS_INLINE +int __libcpp_condvar_timedwait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m, timespec* __ts) +{ + return pthread_cond_timedwait(__cv, __m, __ts); +} + +inline _LIBCPP_ALWAYS_INLINE +int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv) +{ + return pthread_cond_destroy(__cv); +} + +// Thread id +typedef pthread_t __libcpp_thread_id; + +// Returns non-zero if the thread ids are equal, otherwise 0 +inline _LIBCPP_ALWAYS_INLINE +bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2) +{ + return pthread_equal(t1, t2) != 0; +} + +// Returns non-zero if t1 < t2, otherwise 0 +inline _LIBCPP_ALWAYS_INLINE +bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2) +{ + return t1 < t2; +} + +// Thread +typedef pthread_t __libcpp_thread_t; + +inline _LIBCPP_ALWAYS_INLINE +int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg) +{ + return pthread_create(__t, 0, __func, __arg); +} + +inline _LIBCPP_ALWAYS_INLINE +__libcpp_thread_id __libcpp_thread_get_current_id() +{ + return pthread_self(); +} + +inline _LIBCPP_ALWAYS_INLINE +__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t* __t) +{ + return *__t; +} + +inline _LIBCPP_ALWAYS_INLINE +int __libcpp_thread_join(__libcpp_thread_t* __t) +{ + return pthread_join(*__t, 0); +} + +inline _LIBCPP_ALWAYS_INLINE +int __libcpp_thread_detach(__libcpp_thread_t* __t) +{ + return pthread_detach(*__t); +} + +inline _LIBCPP_ALWAYS_INLINE +void __libcpp_thread_yield() +{ + sched_yield(); +} + +// Thread local storage +typedef pthread_key_t __libcpp_tl_key; + +inline _LIBCPP_ALWAYS_INLINE +int __libcpp_tl_create(__libcpp_tl_key* __key, void (*__at_exit)(void*)) +{ + return pthread_key_create(__key, __at_exit); +} + +inline _LIBCPP_ALWAYS_INLINE +void* __libcpp_tl_get(__libcpp_tl_key __key) +{ + return pthread_getspecific(__key); +} + +inline _LIBCPP_ALWAYS_INLINE +void __libcpp_tl_set(__libcpp_tl_key __key, void* __p) +{ + pthread_setspecific(__key, __p); +} + +#else // !_LIBCPP_THREAD_API_PTHREAD + #error "No thread API selected." +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_HAS_NO_THREADS + +#endif // _LIBCPP_THREADING_SUPPORT 
diff --git a/include/mutex b/include/mutex index a0875a5..4d288ae 100644 --- a/include/mutex +++ b/include/mutex 
@@ -179,9 +179,7 @@  #ifndef _LIBCPP_HAS_NO_VARIADICS  #include <tuple>  #endif -#ifndef _LIBCPP_HAS_NO_THREADS -#include <sched.h> -#endif +#include <__threading_support>    #include <__undef_min_max>   @@ -195,7 +193,7 @@    class _LIBCPP_TYPE_VIS recursive_mutex  { - pthread_mutex_t __m_; + __libcpp_mutex_t __m_;    public:  recursive_mutex(); @@ -210,7 +208,7 @@  bool try_lock() _NOEXCEPT;  void unlock() _NOEXCEPT;   - typedef pthread_mutex_t* native_handle_type; + typedef __libcpp_mutex_t* native_handle_type;  _LIBCPP_INLINE_VISIBILITY  native_handle_type native_handle() {return &__m_;}  }; @@ -262,7 +260,7 @@  mutex __m_;  condition_variable __cv_;  size_t __count_; - pthread_t __id_; + __libcpp_thread_id __id_;  public:  recursive_timed_mutex();  ~recursive_timed_mutex(); @@ -288,9 +286,9 @@  recursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)  {  using namespace chrono; - pthread_t __id = pthread_self(); + __libcpp_thread_id __id = __libcpp_thread_get_current_id();  unique_lock<mutex> lk(__m_); - if (pthread_equal(__id, __id_)) + if (__libcpp_thread_id_equal(__id, __id_))  {  if (__count_ == numeric_limits<size_t>::max())  return false; @@ -362,7 +360,7 @@  break;  }  } - sched_yield(); + __libcpp_thread_yield();  {  unique_lock<_L1> __u1(__l1);  if (__l0.try_lock()) @@ -371,7 +369,7 @@  break;  }  } - sched_yield(); + __libcpp_thread_yield();  }  }   @@ -396,7 +394,7 @@  }  }  ++__i; - sched_yield(); + __libcpp_thread_yield();  break;  case 1:  { @@ -412,7 +410,7 @@  __i = 0;  else  __i += 2; - sched_yield(); + __libcpp_thread_yield();  break;  default:  __lock_first(__i - 2, __l2, __l3..., __l0, __l1); 
diff --git a/include/thread b/include/thread index bf5b8e8..3ce32fc 100644 --- a/include/thread +++ b/include/thread 
@@ -98,8 +98,7 @@  #ifndef _LIBCPP_HAS_NO_VARIADICS  #include <tuple>  #endif -#include <pthread.h> -#include <sched.h> +#include <__threading_support>    #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)  #pragma GCC system_header @@ -137,7 +136,7 @@  template <class _Tp>  class __thread_specific_ptr  { - pthread_key_t __key_; + __libcpp_tl_key __key_;    // Only __thread_local_data() may construct a __thread_specific_ptr  // and only with _Tp == __thread_struct. @@ -155,7 +154,7 @@  ~__thread_specific_ptr();    _LIBCPP_INLINE_VISIBILITY - pointer get() const {return static_cast<_Tp*>(pthread_getspecific(__key_));} + pointer get() const {return static_cast<_Tp*>(__libcpp_tl_get(__key_));}  _LIBCPP_INLINE_VISIBILITY  pointer operator*() const {return *get();}  _LIBCPP_INLINE_VISIBILITY @@ -174,7 +173,9 @@  template <class _Tp>  __thread_specific_ptr<_Tp>::__thread_specific_ptr()  { - int __ec = pthread_key_create(&__key_, &__thread_specific_ptr::__at_thread_exit); + int __ec = __libcpp_tl_create( + &__key_, + &__thread_specific_ptr::__at_thread_exit);  #ifndef _LIBCPP_NO_EXCEPTIONS  if (__ec)  throw system_error(error_code(__ec, system_category()), @@ -196,7 +197,7 @@  __thread_specific_ptr<_Tp>::release()  {  pointer __p = get(); - pthread_setspecific(__key_, 0); + __libcpp_tl_set(__key_, nullptr);  return __p;  }   @@ -205,7 +206,7 @@  __thread_specific_ptr<_Tp>::reset(pointer __p)  {  pointer __p_old = get(); - pthread_setspecific(__key_, __p); + __libcpp_tl_set(__key_, __p);  delete __p_old;  }   @@ -226,7 +227,7 @@  // FIXME: pthread_t is a pointer on Darwin but a long on Linux.  // NULL is the no-thread value on Darwin. Someone needs to check  // on other platforms. We assume 0 works everywhere for now. - pthread_t __id_; + __libcpp_thread_id __id_;    public:  _LIBCPP_INLINE_VISIBILITY @@ -234,13 +235,13 @@    friend _LIBCPP_INLINE_VISIBILITY  bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT - {return __x.__id_ == __y.__id_;} + {return __libcpp_thread_id_equal(__x.__id_, __y.__id_);}  friend _LIBCPP_INLINE_VISIBILITY  bool operator!=(__thread_id __x, __thread_id __y) _NOEXCEPT  {return !(__x == __y);}  friend _LIBCPP_INLINE_VISIBILITY  bool operator< (__thread_id __x, __thread_id __y) _NOEXCEPT - {return __x.__id_ < __y.__id_;} + {return __libcpp_thread_id_less(__x.__id_, __y.__id_);}  friend _LIBCPP_INLINE_VISIBILITY  bool operator<=(__thread_id __x, __thread_id __y) _NOEXCEPT  {return !(__y < __x);} @@ -260,7 +261,7 @@    private:  _LIBCPP_INLINE_VISIBILITY - __thread_id(pthread_t __id) : __id_(__id) {} + __thread_id(__libcpp_thread_id __id) : __id_(__id) {}    friend __thread_id this_thread::get_id() _NOEXCEPT;  friend class _LIBCPP_TYPE_VIS thread; @@ -274,7 +275,7 @@  _LIBCPP_INLINE_VISIBILITY  size_t operator()(__thread_id __v) const  { - return hash<pthread_t>()(__v.__id_); + return hash<__libcpp_thread_id>()(__v.__id_);  }  };   @@ -285,20 +286,20 @@  __thread_id  get_id() _NOEXCEPT  { - return pthread_self(); + return __libcpp_thread_get_current_id();  }    } // this_thread    class _LIBCPP_TYPE_VIS thread  { - pthread_t __t_; + __libcpp_thread_t __t_;    thread(const thread&);  thread& operator=(const thread&);  public:  typedef __thread_id id; - typedef pthread_t native_handle_type; + typedef __libcpp_thread_t native_handle_type;    _LIBCPP_INLINE_VISIBILITY  thread() _NOEXCEPT : __t_(0) {} @@ -330,7 +331,7 @@  void join();  void detach();  _LIBCPP_INLINE_VISIBILITY - id get_id() const _NOEXCEPT {return __t_;} + id get_id() const _NOEXCEPT {return __libcpp_thread_get_id(&__t_);}  _LIBCPP_INLINE_VISIBILITY  native_handle_type native_handle() _NOEXCEPT {return __t_;}   @@ -370,7 +371,7 @@  new _Gp(std::move(__tsp),  __decay_copy(_VSTD::forward<_Fp>(__f)),  __decay_copy(_VSTD::forward<_Args>(__args))...)); - int __ec = pthread_create(&__t_, 0, &__thread_proxy<_Gp>, __p.get()); + int __ec = __libcpp_thread_create(&__t_, &__thread_proxy<_Gp>, __p.get());  if (__ec == 0)  __p.release();  else @@ -405,7 +406,7 @@  typedef __thread_invoke_pair<_Fp> _InvokePair;  typedef std::unique_ptr<_InvokePair> _PairPtr;  _PairPtr __pp(new _InvokePair(__f)); - int __ec = pthread_create(&__t_, 0, &__thread_proxy_cxx03<_InvokePair>, __pp.get()); + int __ec = __libcpp_thread_create(&__t_, &__thread_proxy_cxx03<_InvokePair>, __pp.get());  if (__ec == 0)  __pp.release();  else @@ -480,7 +481,7 @@  }    inline _LIBCPP_INLINE_VISIBILITY -void yield() _NOEXCEPT {sched_yield();} +void yield() _NOEXCEPT {__libcpp_thread_yield();}    } // this_thread